package cn.ddiancan.schedule.task.service;

import java.util.Date;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;

import cn.ddiancan.schedule.base.domain.ExecuteTypeEnum;
import cn.ddiancan.schedule.base.domain.TaskDTO;
import cn.ddiancan.schedule.base.domain.TaskLogVO;
import cn.ddiancan.schedule.business.service.IScheduleExecutor;
import com.alibaba.fastjson.JSON;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;

/**
 * 任务线程
 */
@RequiredArgsConstructor
public class SchedulingRunnable implements Runnable {

    private static final Logger logger = LoggerFactory.getLogger(SchedulingRunnable.class);

    private final TaskDTO taskDTO;

    private final ApplicationContext applicationContext;

    private final DistributedLockService distributedLockService;

    @Override
    public void run() {
        long startTime = System.currentTimeMillis();
        // 未接入微服务，无法获取用户上下文，定时任务执行固定为SYSTEM
        taskDTO.setPerformer("System");
        String executeUrl = taskDTO.getExecuteUrl();
        logger.info("定时任务开始执行 - executeUrl：{}，参数：{}", executeUrl, JSON.toJSONString(taskDTO));
        Map<String, IScheduleExecutor> beansOfType = applicationContext.getBeansOfType(IScheduleExecutor.class);
        AtomicReference<IScheduleExecutor> atomicReference = new AtomicReference<>();
        switch (ExecuteTypeEnum.getExecuteTypeEnum(taskDTO.getExecuteType())) {
            case Bean -> atomicReference.set(beansOfType.get("beanTaskExecutor"));
            case URL -> atomicReference.set(beansOfType.get("remoteTaskExecutor"));
            default -> throw new IllegalArgumentException("不支持的任务类型");
        }
        if (distributedLockService.tryLock(taskDTO.getScheduleCode(), 600000)) {
            TaskLogVO taskLogVO = JSON.parseObject(JSON.toJSONString(taskDTO), TaskLogVO.class);
            IScheduleExecutor iScheduleExecutor = Objects.requireNonNull(atomicReference.get());
            try {
                iScheduleExecutor.beforeExecute(taskDTO, this);
                iScheduleExecutor.execute(taskDTO, this);
                taskLogVO.setCostTime(System.currentTimeMillis() - startTime);
                taskLogVO.setExecuteTime(new Date(startTime));
                taskLogVO.setResultMessage("success");
                taskLogVO.setExecuteResult("success");
            } catch (Exception e) {
                taskLogVO.setResultMessage(e.getMessage());
                taskLogVO.setExecuteResult("fail");
            } finally {
                taskLogVO.setExecuteTime(new Date(startTime));
                taskLogVO.setCostTime(System.currentTimeMillis() - startTime);
                iScheduleExecutor.afterExecute(taskLogVO);
                distributedLockService.releaseLock(taskDTO.getScheduleCode());
            }
        }
        long times = System.currentTimeMillis() - startTime;
        logger.info("定时任务执行结束，耗时：{} 毫秒", times);
    }
}
